-
Notifications
You must be signed in to change notification settings - Fork 2.7k
JIT: Transform X % C == 0 to X & (C-1) == 0 #25744
Conversation
Overall seems fine but I'm not sure if this is the best way to do it. Another way is to simply change the existing |
@mikedn hm... indeed! Changed MOD to UMOD. TODO: bool Test1(int year) => year % 4 != 0; // GT_GT instead of GT_NE
int Test2(int year)
{
if (year > 0)
return year % 4; // year is guaranteed to be positive
return 0;
} |
The part about figuring out that |
I don't quite understand where does |
I guess from Roslyn: bool Test1(int year) => year % 4 != 0; IL_0000: ldarg.1
IL_0001: ldc.i4.4
IL_0002: rem
IL_0003: ldc.i4.0
IL_0004: cgt.un
IL_0006: ret
|
Ah, right. I got confused because the code uses |
#9454 does |
@mikedn thanks! will try to play with the order. Btw, F# doesn't generate |
Basically what C# does is an optimization. But AFAIR it's mentioned in ECMA so it's basically an IL idiom so it's perhaps surprising that F# does not use it. |
@dotnet/jit-contrib |
@EgorBo do you expect this to significantly close this regression (which of course was due to a different cause)? https://github.com/dotnet/coreclr/issues/25728 |
@danmosemsft definitely not enough to cover even ~2% of that regression 🙁 (according to my benchmarks) |
@danmosemsft The regression is mostly caused by the different kernel32.dll method being invoked. The P/Invoke itself accounts for bulk of the time difference. |
|
@EgorBo Why are there any regressions? |
@BruceForstall trying to figure out, this the first time I use jittools so probably messed up a bit. bool IsPinned(long handle) => (handle & 1) != 0; // should be a single `and` instruction ; Method ConsoleApp172.Program:IsPinned(long):bool:this
G_M43362_IG01:
G_M43362_IG02:
- test dl, 1
+ mov eax, edx
+ test al, 1
setne al
movzx rax, al
G_M43362_IG03:
ret
-; Total bytes of code: 10
+; Total bytes of code: 11 I guess it's what my |
It appears that the
The change to
That |
Note that the diff you did only has corelib. The entire FX diff is:
|
Workarounded the regression (not sure how to properly fix it):
0 regressions |
@@ -12745,6 +12766,11 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) | |||
oper = (oper == GT_LE) ? GT_EQ : GT_NE; | |||
tree->SetOper(oper, GenTree::PRESERVE_VN); | |||
tree->gtFlags &= ~GTF_UNSIGNED; | |||
|
|||
if (op1->OperIs(GT_MOD)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EgorBo I was trying to review that PR and lost the track of the changes, the first part Transform X MOD C == 0 to X UMOD C == 0
looks clear, but why were this label and goto added?
and it is really scary for me to have a back edge in a function like fgMorphSmpOp
especially for 500 lines length.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sandreenko I wanted to handle X % C != 0
but couldn't just visit GT_NE
node - Roslyn emits cgt.un
(GT_GT) and morph converts it back to GT_NE but doesn't visit GT_NE after. So I have three options to fix the != 0 case:
- Handle unsigned GT_GT node instead of GT_NE
- Convert GT_GT to GT_NE early in the importer
- goto GT_NE (current)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't it be better to call fgMorphSmpOp
recursively here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sandreenko will try, but I think there will be a few regressions
Thank you for your contribution. As announced in dotnet/coreclr#27549 this repository will be moving to dotnet/runtime on November 13. If you would like to continue working on this PR after this date, the easiest way to move the change to dotnet/runtime is:
|
Thank you for your contribution. As announced in #27549 the dotnet/runtime repository will be used going forward for changes to this code base. Closing this PR as no more changes will be accepted into master for this repository. If you’d like to continue working on this change please move it to dotnet/runtime. |
Optimize
X % C == 0
toX & (C-1) == 0
. This expression is used in DateTime.IsLeapYear.C#:
Old:
New:
Will run jit diffs later.